/**
 * @author Sergey Chikuyonok (sc@design.ru)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 * @include "/js-libs/canvas-doc.js"
 */
var rocon = (function(){
	var re_rule = /\.rc(\d+)\b/;
	var re_class = /\brc(\d+)\b/;
	
	/** Префиск для создаваемых CSS-правил */
	var rule_prefix = 'rocon__';
	
	/** Базовый класс для создаваемых элементов */
	var base_class = 'rocon';
	
	var dummy = function(){};
	
	/**
	 * Результат, возвращаемый в объект <code>rocon</code>
	 */
	var result = {
		/**
		 * Добавление/обновление уголков для динамически созданных элементов.
		 * Может принимать неограниченное количество элементов либо массивов
		 * элементов, у которых нужно обновить уголки  
		 */
		update: function(){}
	};
	
	/**
	 * Таблица стилей для уголков
	 * @type {CSSStyleSheet}
	 */
	var corners_ss = null;
	
	/** Кэш для уголков */
	var _corner_cache = {};
	
	var userAgent = navigator.userAgent.toLowerCase();
	
	/**
	 * Тип и версия браузера пользователя. Взято с jQuery
	 */
	var browser = {
		version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1],
		safari: /webkit/.test( userAgent ),
		opera: /opera/.test( userAgent ),
		msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ),
		mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent )
	};
	
	/** Классы элементов, которым нужно добавить скругленные уголки */
	var elem_classes = [];
	
	/**
	 * Список функций, которые нужно выполнить при загрузке DOM-дерева
	 */
	var dom_ready_list = [];
	var is_ready = false, readyBound = false;
	
	/**
	 * Выполняет все функции, добавленные на событие onDomContentLoaded.
	 * Взято с jQuery
	 */
	function fireReady() {
		//Make sure that the DOM is not already loaded
		if (!is_ready) {
			// Remember that the DOM is ready
			is_ready = true;

			// If there are functions bound, to execute
			if ( dom_ready_list.length ) {
				walkArray(dom_ready_list, function(){
					this.call(document);
				});

				// Reset the list of functions
				dom_ready_list = null;
			}
		}
	}
	
	/**
	 * Добавляет слушателя на событие onDomContentLoaded
	 * @type {Function} fn Слушатель
	 */
	function addDomReady(fn) {
		dom_ready_list.push(fn);
	}
	
	/**
	 * Проверка на наступление события onDomContentLoaded. 
	 * Взято с jQuery
	 */
	function bindReady(){
		if ( readyBound ) return;
		readyBound = true;
	
		// Mozilla, Opera and webkit nightlies currently support this event
		if ( document.addEventListener ) {
			// Use the handy event callback
			document.addEventListener( "DOMContentLoaded", function(){
				document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
				fireReady();
			}, false );
	
		// If IE event model is used
		} else if ( document.attachEvent ) {
			// ensure firing before onload,
			// maybe late but safe also for iframes
			document.attachEvent("onreadystatechange", function(){
				if ( document.readyState === "complete" ) {
					document.detachEvent( "onreadystatechange", arguments.callee );
					fireReady();
				}
			});
	
			// If IE and not an iframe
			// continually check to see if the document is ready
			if ( document.documentElement.doScroll && !window.frameElement ) (function(){
				if ( is_ready ) return;
	
				try {
					// If IE is used, use the trick by Diego Perini
					// http://javascript.nwbox.com/IEContentLoaded/
					document.documentElement.doScroll("left");
				} catch( error ) {
					setTimeout( arguments.callee, 0 );
					return;
				}
	
				// and execute any waiting functions
				fireReady();
			})();
		}
	}
	
	/**
	 * Вспомогательная функция, которая пробегается по всем элементам массива
	 * <code>ar</code> и выполняет на каждом элементе его элементе функцию
	 * <code>fn</code>. <code>this</code> внутри этой функции указывает на 
	 * элемент массива
	 * @param {Array} ar Массив, по которому нужно пробежаться
	 * @param {Function} fn Функция, которую нужно выполнить на каждом элементе массива
	 */
	function walkArray(ar, fn) {
		var result;
		for (var i = ar.length - 1; i >= 0; i--) {
			if (fn.call(ar[i], i) === false)
				break;
		}
	}
	
	/**
	 * Функция добавления скругленных уголков элементу. Для каждого браузера 
	 * будет своя функция
	 */
	function addCorners(){
		return;
	};
	
	// TODO Добавить исключение при правильной работе border-radius
	
	/**
	 * Преобразует цвет из RGB-предствления в hex
	 * @param {String} color
	 * @return {String}
	 */
	function convertColorToHex(color) {
		var result;
		function s(num) {
			var n = parseInt(num, 10).toString(16);
			return (n.length == 1) ? n + n : n;
		}
		
		function p(num) {
			return s(Math.round(num * 2.55));
		}
		
		if (result = /rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)/.exec(color))
			return '#' + s(result[1]) + s(result[2]) + s(result[3]);

		// Look for rgb(num%,num%,num%)
		if (result = /rgb\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*\)/.exec(color))
			return '#' + p(result[1]) + p(result[2]) + p(result[3]); 

		// Look for #a0b1c2
		if (result = /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/i.exec(color))
			return '#' + result[1] + result[2] + result[3];
			
		if (result = /#([a-f0-9])([a-f0-9])([a-f0-9])/i.exec(color))
			return '#' + result[1] + result[1] + result[2] + result[2] + result[3] + result[3];
		
		s = null;
		p = null;
			
		return color;
	}
	
	/**
	 * Создает HTML-элемент <code>name</code> с классом <code>class_name</code>
	 * @param {String} name Название элемента
	 * @param {String} class_name Класс элемента
	 * @return {Element}
	 */
	function createElement(name, class_name) {
		var elem = document.createElement(name);
		if (class_name) {
			elem.className = class_name;
		}
		return elem;
	}
	
	/**
	 * Простая проверка наличия определенного класса у элемента
	 * @param {HTMLElement} elem
	 * @param {String} class_name
	 * @return {Boolean}
	 */
	function hasClass(elem, class_name) {
		return elem.nodeType == 1 && (elem.className || '').indexOf(class_name) != -1;
	}
	
	/**
	 * Возвращает значение CSS-свойства <b>name</b> элемента <b>elem</b>
	 * @author John Resig (http://ejohn.org)
	 * @param {Element} elem Элемент, у которого нужно получить значение CSS-свойства
	 * @param {String} name Название CSS-свойства
	 * @return {String}
	 */
	function getStyle(elem, name) {
		var name_camel = name.replace(/\-(\w)/ig, function(str, p1){return p1.toUpperCase();});
		
		// If the property exists in style[], then it's been set
		// recently (and is current)
		if (elem.style[name_camel]) {
			return elem.style[name_camel];
		}
		//Otherwise, try to use IE's method
		else if (browser.msie) {
			return elem.currentStyle[name_camel];
		}
		// Or the W3C's method, if it exists
		else if (document.defaultView && document.defaultView.getComputedStyle) {
			var s = document.defaultView.getComputedStyle(elem, "");
			return s && s.getPropertyValue(name);
		}
		//Otherwise, we're using some other browser
		else {
			return null;
		}
	}
	
	/**
	 * Возвращает цвет фона элемента
	 * @type {Function}
	 * @param {Element} elem Элемент, для которого нужно достать цвет фона
	 */
	var getBg = (function() {
	
		var session_elems = [];
		
		/**
		 * Основной цикл с использованием кэширования
		 */
		function mainLoopCache(elem) {
			var c;
			do {
				if (elem.nodeType != 1)
					break;
				
				if (elem.rocon_bg) { // цвет был найден ранее
					return elem.rocon_bg;
				} else { // цвет еще не найден
					session_elems.push(elem);
					c = getStyle(elem, 'background-color');
					if (c != 'transparent')
						return convertColorToHex(c);
				}
					
			} while (elem = elem.parentNode);
			
			return '#ffffff';
		}
		
		/**
		 * Основной цикл без кэширования
		 */
		function mainLoopNoCache(elem) {
			var c;
			do {
				if (elem.nodeType != 1)
					break;
					
				c = getStyle(elem, 'background-color');
				if (c != 'transparent')
					return convertColorToHex(c);
					
			} while (elem = elem.parentNode);
			
			return '#ffffff';
		}
		
		return function(elem){
			var bg;
			if (getBg.use_cache) {
				session_elems = [];
				bg = mainLoopCache(elem);
				// закэшируем цвет фона у всех элементов, по которым проходились
				walkArray(session_elems, function(){
					this.rocon_bg = bg;
					getBg.processed_elems.push(this);
				});
				
				session_elems = null;
			} else {
				bg = mainLoopNoCache(elem);
			}
			
			return bg;
		}
	})();
	
	getBg.use_cache = true;
	getBg.processed_elems = [];
	
	/**
	 * Добавляет CSS-правило в стиль
	 * @param {String} selector CSS-селектор, для которого нужно добавить правила
	 * @param {String} rules CSS-правила
	 */
	function addRule(selector, rules) {
		corners_ss.insertRule(selector + ' {' + rules + '}', corners_ss.cssRules.length);
	}
	
	/**
	 * Функция поиска правил для скругленных уголков
	 * @param {Function} addFunc Функция добавления уголков
	 */
	function findRules(addFunc) {
		/** @type {String[]}  */
		var match;
		
		walkArray(document.styleSheets, function(){
			walkArray(this.cssRules || this.rules, function(){
				if (match = re_rule.exec(this.selectorText))
					addFunc(this, parseInt(match[1], 10));
			});
		});
	}
	
	/**
	 * Очищает элемент от предыдущих вставок скругленных уголков
	 * @param {Element} elem
	 * @return {Element} Переданный элемент
	 */
	function cleanUp(elem) {
		elem.className = (elem.className || '').replace(/\b\s*rocon\w*/ig, '');
		return elem;
	}
	
		
	/**
	 * Функция добавления правил для скругленных уголков
	 */
	function addRoundedProperties(/* CSSStyleRule */ rule, /* Number */ radius) {
		elem_classes.push(rule.selectorText.substr(1));
	}
	
	/**
	 * Обрабатывает все элементы на странице, которым нужно добавить скругленные
	 * уголки
	 */
	function processRoundedElements(){
		// Опера автоматически обновляет NodeList при добавлении новых
		// элементов в дерево, поэтому создаем обычный массив элементов
		var elems = [];
		walkArray(document.getElementsByTagName('*'), function(){
			elems.push(this);
		});
		
		// собираем регулярное выражение по которому будем определять,
		// нужно ли добавлять элементу уголки
		var re_classes = new RegExp('(^|\\s)(' + elem_classes.join('|') + ')(\\s|$)');
		walkArray(elems, function(){
			if (re_classes.test(this.className || '')) 
				addCorners(this);
		});
	}
	
	/**
	 * Рисует «звездочку» через canvas
	 * @param {Number} radius Радиус скругления
	 * @param {String} color Цвет уголка в hex-формате
	 * @return {String} Картинка в формате data:URL
	 */
	function drawStar(radius, color, border_width, border_color) {
		if (!drawStar.cv) {
			drawStar.cv = createElement('canvas');
		}
		
		border_width = (border_width > radius) ? radius : border_width;
		
		if (border_width > 1)
			radius -= border_width / 2;
			
		
		var width = (radius * 2 + border_width), height = width;
		
		if (border_width == 1) {
			width--;
			height--;
			
		}
	
		drawStar.cv.width = width;
		drawStar.cv.height = height;
		
//		var b2 = (border_width > 1) ? Math.ceil(border_width / 2) * 2 : 0;
		var b2 = (border_width > 1) ? border_width : 0;
		
		/** @type {CanvasRenderingContext2D} */
		var ctx = drawStar.cv.getContext('2d');
		
		ctx.strokeStyle = border_color;
		ctx.lineWidth = border_width;
		ctx.lineJoin = 'miter';
		ctx.lineCap = 'square';
		ctx.fillStyle = (color.charAt(0) != '#') ? '#' + color : color;
		
		
		ctx.clearRect(0, 0, width, height);
	//	ctx.fillStyle = '#00f';
	//	ctx.fillRect(0, 0, width, height);
		
		var deg90 = Math.PI / 2;
		
	//	ctx.translate(-border_width / 4, -border_width / 4);
	
		ctx.beginPath();
		ctx.arc(0, 0, radius, deg90, 0, true);
		ctx.arc(radius + radius + b2, 0, radius, deg90 * 2, deg90, true);
		ctx.arc(radius + radius + b2, radius * 2 + b2, radius, -deg90, deg90 * 2, true);
		ctx.arc(0, radius * 2 + b2, radius, 0, -deg90, true);
		ctx.closePath();
		ctx.fill();
		
		if (border_width) {
			ctx.beginPath();
			ctx.arc(0, 0, radius, deg90, 0, true);
			ctx.stroke();
			
			ctx.beginPath();
			ctx.arc(radius + radius + b2, 0, radius, deg90 * 2, deg90, true);
			ctx.stroke();
			
			ctx.beginPath();
			ctx.arc(radius + radius + b2, radius * 2 + b2, radius, -deg90, deg90 * 2, true);
			ctx.stroke();
		
			ctx.beginPath();
			ctx.arc(0, radius * 2 + b2, radius, 0, -deg90, true);
			ctx.stroke();
		}
		
		return drawStar.cv.toDataURL();
	}
	
	/**
	 * Возвращает параметры уголка элемента
	 * @param {Element} elem Элемент, у которого нужно получить параметры уголка
	 */
	function getCornerParams(elem) {
		var radius = parseInt(elem.className.match(re_class)[1], 10);
		var bg_color = getBg(elem.parentNode);
		
		var border_color = '';
		var border_width = parseInt(getStyle(elem, 'border-left-width')) || 0;
		if (border_width) {
			// нужно отрисовать бордюр
			border_color = convertColorToHex(getStyle(elem, 'border-left-color') || '#000');
		}
		
		return {
			'radius': radius,
			'bg_color': bg_color,
			
			// толщина бордюра не может быть больше радиуса скругления
			// (так по CSS3 спецификации)
			'border_width': (border_width > radius) ? radius : border_width,
			'real_border_width': border_width,
			'border_color': border_color
		};
	}
	
	/*
	 * Так как нам очень важна производительность этого механизма, а для разных 
	 * браузеров надо применять различные схемы добавления уголков, я сделаю
	 * предварительную компиляцию функций под каждый браузер.
	 * 
	 * Это значит, что я один раз «скомпилирую» некоторые функции типа 
	 * addCorners(), чтобы избежать большого количества проверок во время 
	 * работы библиотеки.
	 */
	if (browser.mozilla) { //для дебага временно отключу
		addRoundedProperties = function(/* CSSStyleRule */ rule, /* Number */ radius) {
			rule.style.MozBorderRadius = radius + 'px';
		};
	} else if (browser.safari) {
		addRoundedProperties = function(/* CSSStyleRule */ rule, /* Number */ radius) {
			rule.style.WebkitBorderRadius = radius + 'px';
			rule.style.KhtmlBorderRadius = radius + 'px';
		};
	} else if (browser.opera) {
		/*
		 * С Оперой и IE все гораздо сложнее: нужно дожаться, пока загрузится
		 * DOM-дерево, после чего получить все элементы, которым нужно 
		 * скруглить уголки, и добавить соотвествующие стили и элементы
		 */
		
		/**
		 * Создает базовые CSS-стили для управления уголками 
		 */
		function createStylesheetForOpera() {
			var style = createElement('style');
			document.getElementsByTagName('head')[0].appendChild(style);
			corners_ss = document.styleSheets[document.styleSheets.length - 1];
			addRule('.' + base_class, 'position:absolute;background-repeat:no-repeat;z-index:1;display:none');
			addRule('.' + base_class + '-init', 'position:relative;');
			addRule('.' + base_class + '-init>.' + base_class, 'display:inline-block;');
			addRule('.' + base_class + '-tl', 'top:0;left:0;background-position:100% 100%;');
			addRule('.' + base_class + '-tr', 'top:0;right:0;background-position:0 100%;');
			addRule('.' + base_class + '-bl', 'bottom:0;left:0;background-position:100% 0;');
			addRule('.' + base_class + '-br', 'bottom:0;right:0;');
		}
		
		/**
		 * Создает CSS-правила для уголков определенного радиуса и цвета
		 * @param {getCornerParams()} cparams Параметры скругления блока
		 * @return {String} Имя класса, которое нужно присвоить элементу
		 */
		function createCornerRules(cparams) {
			var cache_key = [cparams.radius, cparams.bg_color, cparams.real_border_width, cparams.border_color].join(':');
			// смотрим, делали ли правило с такими же параметрами
			if (!_corner_cache[cache_key]) {
				// создаем новое правило
				var cur_class = rule_prefix + corners_ss.cssRules.length;
				_corner_cache[cache_key] = cur_class;
				
				addRule('.' + cur_class + '>.' + base_class, 
					'background-image: url("' + drawStar(cparams.radius, cparams.bg_color, cparams.border_width, cparams.border_color) + '");' +
					'width: '+ cparams.radius +'px;' +
					'height: ' + cparams.radius + 'px;'
				);
				
				// для уголков с бордюрами нужно указать смещение
				if (cparams.border_width) {
					var bw = cparams.real_border_width;
					addRule('.' + cur_class + '>.' + base_class + '-tl', 'top: -'+ bw +'px; left: -'+ bw +'px');
					addRule('.' + cur_class + '>.' + base_class + '-tr', 'top: -'+ bw +'px; right: -'+ bw +'px');
					addRule('.' + cur_class + '>.' + base_class + '-bl', 'bottom: -'+ bw +'px; left: -'+ bw +'px');
					addRule('.' + cur_class + '>.' + base_class + '-br', 'bottom: -'+ bw +'px; right: -'+ bw +'px');
				}
			}
			
			return _corner_cache[cache_key];
		}
	
		/**
		 * Добавляет уголки элементу
		 * @param {Element} elem
		 */
		addCorners = function(elem){
			// если у элемента нет класса — значит, нет указания, какие уголки
			// нужно добавить
			if (!elem.className)
				return;
			
			if (!corners_ss)
				createStylesheetForOpera();
			
			// проверим, нужно ли добавлять элементы с уголками
			var dont_add = false;
			walkArray(elem.childNodes, function(){
				if (hasClass(this, base_class)) {
					dont_add = true;
					return false;
				}
			});
			
			elem.className += ' ' + createCornerRules( getCornerParams(elem) );
			
			if (!dont_add) 
				// добавляем уголки
				walkArray(['tl', 'tr', 'bl', 'br'], function(){
					elem.appendChild( createElement('span', base_class + ' ' + base_class +'-' + this) );
				});
			
			elem.className += ' ' + base_class + '-init';
		};
		
		addDomReady(processRoundedElements);
		addDomReady(function(){
			/*
			 * Одна из причин, по которой я ненавижу Оперу — это 
			 * необходимость до сих пор вставлять подобные костыли, 
			 * чтобы что-то отобразились на странице
			 */
			document.documentElement.style.outline = 'none';
		});
		
		result.update = function() {
			walkArray(arguments, function(){
				walkArray((this instanceof Array) ? this : [this], function(){
					addCorners( cleanUp(this) );
				});
			});
		}
		
	} else if (browser.msie) {
		// уголки для IE создаем через VML
		_corner_cache.ix = 0;
		_corner_cache.created = {};
		
		function createStylesheetForIE() {
			corners_ss = document.createStyleSheet();
			try {
				if (!document.namespaces["v"]) {
					var dot_class = '.' + base_class;
					document.namespaces.add("v", "urn:schemas-microsoft-com:vml");
					corners_ss.cssText = "v\\:* {behavior:url(#default#VML);display:inline-block;}" +
						dot_class + "-init {position:relative;zoom:1;}" +
						dot_class + " {position:absolute; display:inline-block; zoom: 1;}" +
						dot_class + "-tl v\\:shape{flip: 'y'}" +
						dot_class + "-tr v\\:shape{rotation: 180;}" +
						dot_class + "-br v\\:shape{flip: 'x'}";
						
					if (browser.version < 7) {
						corners_ss.cssText += dot_class + '-tr, ' + dot_class + '-br {margin-left: 100%;}' +
								dot_class + ' v\\:shape{position:absolute}' +
								dot_class + '-tr v\\:shape{right: 0}';
					}
				}
			} catch(e) {
				
			}
		}
		
		addRule = function(selector, rules){
			corners_ss.addRule(selector, rules);
		};
		
		/**
		 * Создает элемент со скругленным уголком. В функции используется
		 * кэширование, то есть ранее созданный уголок дублируется, 
		 * а не создается заново 
		 * @param {Number} radius Радиус скругления
		 * @param {Number} border_width Толщина бордюра
		 * @return {HTMLElement}
		 */
		function createCornerElementIE(radius, border_width) {
			var cache_key = radius + ':' + border_width;
			
			if (!createCornerElementIE._cache[cache_key]) { // элемент еще не создан
				
				var multiplier = 10;
				
				var cv = createElement('v:shape');
				cv.strokeweight = border_width + 'px';
				cv.stroked = (border_width) ? true : false;
				var stroke = createElement('v:stroke');
				stroke.joinstyle = 'miter';
				cv.appendChild(stroke);
				
				var w = radius, h = w;
				
				cv.style.width = w + 'px';
				cv.style.height = h + 'px';
				
				radius -= border_width / 2;
				radius *= multiplier;
				var bo = border_width / 2 * multiplier;
				var px = Math.round((radius + bo) / w);
				var rbo = radius + bo;
				
				cv.coordorigin = Math.round(px / 2) + ' ' + Math.round(px / 2);
				cv.coordsize = rbo + ' ' + rbo;
				cv.path = 'm0,0 ns l' + bo +',0  qy' + rbo + ',' + radius + ' l' + rbo + ',' + rbo + ' l0,' + rbo + ' e ' + 
					'm' + bo + ',' + (-px) + ' nf l' + bo + ',0 qy' + rbo + ',' + radius + ' l ' + (rbo + px) +','+ radius +' e x';
					
				createCornerElementIE._cache[cache_key] = cv;
			}
			
			return createCornerElementIE._cache[cache_key].cloneNode(true);
		}
		
		createCornerElementIE._cache = {};
		
		/**
		 * Создает скругленный уголок
		 * @param {getCornerParams()} cparams параметры уголка
		 * @param {String} type Тип уголка (tl, tr, bl, br)
		 */
		function drawCornerIE(cparams, type){
			var cv = createCornerElementIE(cparams.radius, cparams.border_width);
			cv.fillcolor = cparams.bg_color || '#000';
			cv.strokecolor = cparams.border_color || '#000';
			
			var elem = createElement('span', base_class + ' ' + base_class + '-' + type);
			elem.appendChild(cv);
			
			return elem;
		}
		
		/**
		 * Удаляет у элемента старые уголки
		 * @param {HTMLElement} elem Элемент, у которого нужно удалить уголки 
		 */
		function removeOldCorners(elem) {
			walkArray(elem.childNodes, function(){
				if (hasClass(this, base_class)) {
					elem.removeChild(this);
				}
			});
			
			cleanUp(elem);
		}
		
		/**
		 * Возвращает имя класса для переданных параметров. Используется для 
		 * того, чтобы не плодить много разных классов для одних и тех же правил
		 * @param {Number} radius Радиус скругления уголка
		 * @param {Number} border_width Толщина бордюра
		 * @return {String}
		 */
		function getClassName(radius, border_width) {
			border_width = border_width || 0;
			var key = radius + ':' + border_width;
			if (!_corner_cache[key]) {
				_corner_cache[key] = rule_prefix + _corner_cache.ix++;
			}
			
			return _corner_cache[key];
		}
		
		/**
		 * Создает CSS-правила для скругленных уголков
		 * @param {Number} radius Радиус скругления
		 * @param {Number} border_width Толщина бордюра
		 */
		function createCSSRules(radius, border_width) {
			border_width = border_width || 0;
			var class_name = getClassName(radius, border_width);
			if (!_corner_cache.created[class_name]) {
				// такое правило еще не создано в CSS, создадим его
				var prefix;
				
				if (browser.version < 7) {
					prefix = '.' + class_name + ' .' + base_class;
					
					addRule(
						prefix + ' -tl', 
						'left:' + (-border_width) + 'px; ' +
							'top:' + (-1 - border_width) + 'px;'
					);
					
					addRule(
						prefix + '-tr', 
						'left:' + ( border_width - 1 ) + 'px; ' +
							'width: ' + (1) + 'px; ' +
							'top:' + (-1 - border_width) + 'px;'
					);
					
					addRule(
						prefix + '-bl', 
						'left:' + (- border_width) + 'px; ' +
							'bottom:' + (-border_width) + 'px;' +
							'height:' + radius + 'px'
					);
					
					addRule(
						prefix + '-br', 
						'left:' + (-radius + border_width - 1) + 'px; ' +
							'width: ' + (radius) + 'px; ' +
							'bottom:' + (-border_width) + 'px;' +
							'height:' + radius + 'px'
					);
				} else {
					prefix = '.' + class_name + '>.' + base_class;
					addRule(
						prefix + '-tl', 
						'left:' + (-1 - border_width) + 'px; ' +
							'top:' + (-1 - border_width) + 'px;'
					);
					
					addRule(
						prefix + '-tr', 
						'right:' + ( - border_width) + 'px; ' +
							'top:' + (-1 - border_width) + 'px;'
					);
					
					addRule(
						prefix + '-bl', 
						'left:' + (-1 - border_width) + 'px; ' +
							'bottom:' + (-border_width) + 'px;'
					);
					
					addRule(
						prefix + '-br', 
						'right:' + (-border_width) + 'px; ' +
							'bottom:' + (-border_width) + 'px;'
					);
					
				}
				
				
				_corner_cache.created[class_name] = true;
			}
		}
		
		addCorners = function(elem) {
			if (!corners_ss)
				createStylesheetForIE();
			
			var cparams = getCornerParams(elem);
			
			createCSSRules(cparams.radius, cparams.real_border_width);
			
//			// теперь добавляем сами уголки в элемент
			walkArray(['tl', 'tr', 'bl', 'br'], function(){
				elem.appendChild(drawCornerIE(cparams, this));
			});
			
			// говорим, что все добавилось
			elem.className += ' ' + getClassName(cparams.radius, cparams.real_border_width) + ' ' + base_class + '-init';
		};
		
		addDomReady(processRoundedElements);
		
		result.update = function() {
			walkArray(arguments, function(){
				walkArray((this instanceof Array) ? this : [this], function(){
					removeOldCorners(this);
					addCorners(this);
				});
			});
		}
	}
	
	
	findRules(addRoundedProperties);
	
	// после того, как добавили уголки, необходимо очистить кэш фона,
	// иначе будут проблемы с динамическим обновлением блоков
	addDomReady(function(){
		walkArray(getBg.processed_elems, function(){
			this.removeAttribute('rocon_bg');
		});
		getBg.use_cache = false;
	})
	
	bindReady();
	
	return result || {}; // скобки в конце для того, чтобы Spket показывал outline :)
})();